home *** CD-ROM | disk | FTP | other *** search
/ Software of the Month Club 2000 October / Software of the Month - Ultimate Collection Shareware 277.iso / pc / PROGRAMS / UTILITY / WINLINUX / DATA1.CAB / programs_-_include / ASM-MIPS / UACCESS.H < prev    next >
C/C++ Source or Header  |  1999-09-17  |  12KB  |  485 lines

  1. /*
  2.  * include/asm-mips/uaccess.h
  3.  *
  4.  * This file is subject to the terms and conditions of the GNU General Public
  5.  * License.  See the file "COPYING" in the main directory of this archive
  6.  * for more details.
  7.  *
  8.  * Copyright (C) 1996, 1997, 1998 by Ralf Baechle
  9.  *
  10.  * $Id: uaccess.h,v 1.15 1998/05/03 11:13:54 ralf Exp $
  11.  */
  12. #ifndef __ASM_MIPS_UACCESS_H
  13. #define __ASM_MIPS_UACCESS_H
  14.  
  15. #include <linux/errno.h>
  16. #include <linux/sched.h>
  17.  
  18. #define STR(x)  __STR(x)
  19. #define __STR(x)  #x
  20.  
  21. /*
  22.  * The fs value determines whether argument validity checking should be
  23.  * performed or not.  If get_fs() == USER_DS, checking is performed, with
  24.  * get_fs() == KERNEL_DS, checking is bypassed.
  25.  *
  26.  * For historical reasons, these macros are grossly misnamed.
  27.  */
  28. #define KERNEL_DS    ((mm_segment_t) { 0UL })
  29. #define USER_DS        ((mm_segment_t) { 1UL })
  30.  
  31. #define VERIFY_READ    0
  32. #define VERIFY_WRITE   1
  33.  
  34. #define get_fs()        (current->tss.current_ds)
  35. #define get_ds()    (KERNEL_DS)
  36. #define set_fs(x)       (current->tss.current_ds=(x))
  37.  
  38. #define segment_eq(a,b)    ((a).seg == (b).seg)
  39.  
  40.  
  41. /*
  42.  * Is a address valid? This does a straighforward calculation rather
  43.  * than tests.
  44.  *
  45.  * Address valid if:
  46.  *  - "addr" doesn't have any high-bits set
  47.  *  - AND "size" doesn't have any high-bits set
  48.  *  - AND "addr+size" doesn't have any high-bits set
  49.  *  - OR we are in kernel mode.
  50.  */
  51. #define __access_ok(addr,size,mask) \
  52.         (((__signed__ long)((mask)&(addr | size | (addr+size)))) >= 0)
  53. #define __access_mask (-(long)(get_fs().seg))
  54.  
  55. #define access_ok(type,addr,size) \
  56. __access_ok(((unsigned long)(addr)),(size),__access_mask)
  57.  
  58. extern inline int verify_area(int type, const void * addr, unsigned long size)
  59. {
  60.     return access_ok(type,addr,size) ? 0 : -EFAULT;
  61. }
  62.  
  63. /*
  64.  * Uh, these should become the main single-value transfer routines ...
  65.  * They automatically use the right size if we just have the right
  66.  * pointer type ...
  67.  *
  68.  * As MIPS uses the same address space for kernel and user data, we
  69.  * can just do these as direct assignments.
  70.  *
  71.  * Careful to not
  72.  * (a) re-use the arguments for side effects (sizeof is ok)
  73.  * (b) require any knowledge of processes at this stage
  74.  */
  75. #define put_user(x,ptr)    __put_user_check((x),(ptr),sizeof(*(ptr)),__access_mask)
  76. #define get_user(x,ptr) __get_user_check((x),(ptr),sizeof(*(ptr)),__access_mask)
  77.  
  78. /*
  79.  * The "__xxx" versions do not do address space checking, useful when
  80.  * doing multiple accesses to the same area (the user has to do the
  81.  * checks by hand with "access_ok()")
  82.  */
  83. #define __put_user(x,ptr) __put_user_nocheck((x),(ptr),sizeof(*(ptr)))
  84. #define __get_user(x,ptr) __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
  85.  
  86. /*
  87.  * The "xxx_ret" versions return constant specified in third argument, if
  88.  * something bad happens. These macros can be optimized for the
  89.  * case of just returning from the function xxx_ret is used.
  90.  */
  91.  
  92. #define put_user_ret(x,ptr,ret) ({ \
  93. if (put_user(x,ptr)) return ret; })
  94.  
  95. #define get_user_ret(x,ptr,ret) ({ \
  96. if (get_user(x,ptr)) return ret; })
  97.  
  98. #define __put_user_ret(x,ptr,ret) ({ \
  99. if (__put_user(x,ptr)) return ret; })
  100.  
  101. #define __get_user_ret(x,ptr,ret) ({ \
  102. if (__get_user(x,ptr)) return ret; })
  103.  
  104. struct __large_struct { unsigned long buf[100]; };
  105. #define __m(x) (*(struct __large_struct *)(x))
  106.  
  107. /*
  108.  * Yuck.  We need two variants, one for 64bit operation and one
  109.  * for 32 bit mode and old iron.
  110.  */
  111. #ifdef __mips64
  112. #define __GET_USER_DW __get_user_asm("ld")
  113. #else
  114. #define __GET_USER_DW __get_user_asm_ll32
  115. #endif
  116.  
  117. #define __get_user_nocheck(x,ptr,size) ({ \
  118. long __gu_err; \
  119. __typeof(*(ptr)) __gu_val; \
  120. long __gu_addr; \
  121. __asm__("":"=r" (__gu_val)); \
  122. __gu_addr = (long) (ptr); \
  123. __asm__("":"=r" (__gu_err)); \
  124. switch (size) { \
  125. case 1: __get_user_asm("lb"); break; \
  126. case 2: __get_user_asm("lh"); break; \
  127. case 4: __get_user_asm("lw"); break; \
  128. case 8: __GET_USER_DW; break; \
  129. default: __get_user_unknown(); break; \
  130. } x = (__typeof__(*(ptr))) __gu_val; __gu_err; })
  131.  
  132. #define __get_user_check(x,ptr,size,mask) ({ \
  133. long __gu_err; \
  134. __typeof__(*(ptr)) __gu_val; \
  135. long __gu_addr; \
  136. __asm__("":"=r" (__gu_val)); \
  137. __gu_addr = (long) (ptr); \
  138. __asm__("":"=r" (__gu_err)); \
  139. if (__access_ok(__gu_addr,size,mask)) { \
  140. switch (size) { \
  141. case 1: __get_user_asm("lb"); break; \
  142. case 2: __get_user_asm("lh"); break; \
  143. case 4: __get_user_asm("lw"); break; \
  144. case 8: __GET_USER_DW; break; \
  145. default: __get_user_unknown(); break; \
  146. } } x = (__typeof__(*(ptr))) __gu_val; __gu_err; })
  147.  
  148. #define __get_user_asm(insn) \
  149. ({ \
  150. __asm__ __volatile__( \
  151.     "1:\t" insn "\t%1,%2\n\t" \
  152.     "move\t%0,$0\n" \
  153.     "2:\n\t" \
  154.     ".section\t.fixup,\"ax\"\n" \
  155.     "3:\tli\t%0,%3\n\t" \
  156.     "move\t%1,$0\n\t" \
  157.     "j\t2b\n\t" \
  158.     ".previous\n\t" \
  159.     ".section\t__ex_table,\"a\"\n\t" \
  160.     ".word\t1b,3b\n\t" \
  161.     ".previous" \
  162.     :"=r" (__gu_err), "=r" (__gu_val) \
  163.     :"o" (__m(__gu_addr)), "i" (-EFAULT)); })
  164.  
  165. /*
  166.  * Get a long long 64 using 32 bit registers.
  167.  */
  168. #define __get_user_asm_ll32 \
  169. ({ \
  170. __asm__ __volatile__( \
  171.     "1:\tlw\t%1,%2\n" \
  172.     "2:\tlw\t%D1,%3\n\t" \
  173.     "move\t%0,$0\n" \
  174.     "3:\t.section\t.fixup,\"ax\"\n" \
  175.     "4:\tli\t%0,%4\n\t" \
  176.     "move\t%1,$0\n\t" \
  177.     "move\t%D1,$0\n\t" \
  178.     "j\t3b\n\t" \
  179.     ".previous\n\t" \
  180.     ".section\t__ex_table,\"a\"\n\t" \
  181.     ".word\t1b,4b\n\t" \
  182.     ".word\t2b,4b\n\t" \
  183.     ".previous" \
  184.     :"=r" (__gu_err), "=&r" (__gu_val) \
  185.     :"o" (__m(__gu_addr)), "o" (__m(__gu_addr + 4)), \
  186.      "i" (-EFAULT)); })
  187.  
  188. extern void __get_user_unknown(void);
  189.  
  190. /*
  191.  * Yuck.  We need two variants, one for 64bit operation and one
  192.  * for 32 bit mode and old iron.
  193.  */
  194. #ifdef __mips64
  195. #define __PUT_USER_DW __put_user_asm("sd")
  196. #else
  197. #define __PUT_USER_DW __put_user_asm_ll32
  198. #endif
  199.  
  200. #define __put_user_nocheck(x,ptr,size) ({ \
  201. long __pu_err; \
  202. __typeof__(*(ptr)) __pu_val; \
  203. long __pu_addr; \
  204. __pu_val = (x); \
  205. __pu_addr = (long) (ptr); \
  206. __asm__("":"=r" (__pu_err)); \
  207. switch (size) { \
  208. case 1: __put_user_asm("sb"); break; \
  209. case 2: __put_user_asm("sh"); break; \
  210. case 4: __put_user_asm("sw"); break; \
  211. case 8: __PUT_USER_DW; break; \
  212. default: __put_user_unknown(); break; \
  213. } __pu_err; })
  214.  
  215. #define __put_user_check(x,ptr,size,mask) ({ \
  216. long __pu_err; \
  217. __typeof__(*(ptr)) __pu_val; \
  218. long __pu_addr; \
  219. __pu_val = (x); \
  220. __pu_addr = (long) (ptr); \
  221. __asm__("":"=r" (__pu_err)); \
  222. if (__access_ok(__pu_addr,size,mask)) { \
  223. switch (size) { \
  224. case 1: __put_user_asm("sb"); break; \
  225. case 2: __put_user_asm("sh"); break; \
  226. case 4: __put_user_asm("sw"); break; \
  227. case 8: __PUT_USER_DW; break; \
  228. default: __put_user_unknown(); break; \
  229. } } __pu_err; })
  230.  
  231. #define __put_user_asm(insn) \
  232. ({ \
  233. __asm__ __volatile__( \
  234.     "1:\t" insn "\t%1,%2\n\t" \
  235.     "move\t%0,$0\n" \
  236.     "2:\n\t" \
  237.     ".section\t.fixup,\"ax\"\n" \
  238.     "3:\tli\t%0,%3\n\t" \
  239.     "j\t2b\n\t" \
  240.     ".previous\n\t" \
  241.     ".section\t__ex_table,\"a\"\n\t" \
  242.     ".word\t1b,3b\n\t" \
  243.     ".previous" \
  244.     :"=r" (__pu_err) \
  245.     :"r" (__pu_val), "o" (__m(__pu_addr)), "i" (-EFAULT)); })
  246.  
  247. #define __put_user_asm_ll32 \
  248. ({ \
  249. __asm__ __volatile__( \
  250.     "1:\tsw\t%1,%2\n\t" \
  251.     "2:\tsw\t%D1,%3\n" \
  252.     "move\t%0,$0\n" \
  253.     "3:\n\t" \
  254.     ".section\t.fixup,\"ax\"\n" \
  255.     "4:\tli\t%0,%4\n\t" \
  256.     "j\t3b\n\t" \
  257.     ".previous\n\t" \
  258.     ".section\t__ex_table,\"a\"\n\t" \
  259.     ".word\t1b,4b\n\t" \
  260.     ".word\t2b,4b\n\t" \
  261.     ".previous" \
  262.     :"=r" (__pu_err) \
  263.     :"r" (__pu_val), "o" (__m(__pu_addr)), "o" (__m(__pu_addr + 4)), \
  264.      "i" (-EFAULT)); })
  265.  
  266. extern void __put_user_unknown(void);
  267.  
  268. #define copy_to_user_ret(to,from,n,retval) ({ \
  269. if (copy_to_user(to,from,n)) \
  270.         return retval; \
  271. })
  272.  
  273. #define copy_from_user_ret(to,from,n,retval) ({ \
  274. if (copy_from_user(to,from,n)) \
  275.         return retval; \
  276. })
  277.  
  278. extern size_t __copy_user(void *__to, const void *__from, size_t __n);
  279.  
  280. #define __copy_to_user(to,from,n) ({ \
  281.     void *__cu_to; \
  282.     const void *__cu_from; \
  283.     long __cu_len; \
  284.     \
  285.     __cu_to = (to); \
  286.     __cu_from = (from); \
  287.     __cu_len = (n); \
  288.     __asm__ __volatile__( \
  289.         "move\t$4, %1\n\t" \
  290.         "move\t$5, %2\n\t" \
  291.         "move\t$6, %3\n\t" \
  292.         "jal\t__copy_user\n\t" \
  293.         "move\t%0, $6" \
  294.         : "=r" (__cu_len) \
  295.         : "r" (__cu_to), "r" (__cu_from), "r" (__cu_len) \
  296.         : "$4", "$5", "$6", "$8", "$9", "$10", "$11", "$12", "$15", \
  297.           "$24", "$31","memory"); \
  298.     __cu_len; \
  299. })
  300.  
  301. #define __copy_from_user(to,from,n) ({ \
  302.     void *__cu_to; \
  303.     const void *__cu_from; \
  304.     long __cu_len; \
  305.     \
  306.     __cu_to = (to); \
  307.     __cu_from = (from); \
  308.     __cu_len = (n); \
  309.     __asm__ __volatile__( \
  310.         "move\t$4, %1\n\t" \
  311.         "move\t$5, %2\n\t" \
  312.         "move\t$6, %3\n\t" \
  313.         ".set\tnoat\n\t" \
  314.         "addu\t$1, %2, %3\n\t" \
  315.         ".set\tat\n\t" \
  316.         "jal\t__copy_user\n\t" \
  317.         "move\t%0, $6" \
  318.         : "=r" (__cu_len) \
  319.         : "r" (__cu_to), "r" (__cu_from), "r" (__cu_len) \
  320.         : "$4", "$5", "$6", "$8", "$9", "$10", "$11", "$12", "$15", \
  321.           "$24", "$31","memory"); \
  322.     __cu_len; \
  323. })
  324.  
  325. #define copy_to_user(to,from,n) ({ \
  326.     void *__cu_to; \
  327.     const void *__cu_from; \
  328.     long __cu_len; \
  329.     \
  330.     __cu_to = (to); \
  331.     __cu_from = (from); \
  332.     __cu_len = (n); \
  333.     if (access_ok(VERIFY_WRITE, __cu_to, __cu_len)) \
  334.         __asm__ __volatile__( \
  335.             "move\t$4, %1\n\t" \
  336.             "move\t$5, %2\n\t" \
  337.             "move\t$6, %3\n\t" \
  338.             "jal\t__copy_user\n\t" \
  339.             "move\t%0, $6" \
  340.             : "=r" (__cu_len) \
  341.             : "r" (__cu_to), "r" (__cu_from), "r" (__cu_len) \
  342.             : "$4", "$5", "$6", "$8", "$9", "$10", "$11", "$12", \
  343.               "$15", "$24", "$31","memory"); \
  344.     __cu_len; \
  345. })
  346.  
  347. #define copy_from_user(to,from,n) ({ \
  348.     void *__cu_to; \
  349.     const void *__cu_from; \
  350.     long __cu_len; \
  351.     \
  352.     __cu_to = (to); \
  353.     __cu_from = (from); \
  354.     __cu_len = (n); \
  355.     if (access_ok(VERIFY_READ, __cu_from, __cu_len)) \
  356.         __asm__ __volatile__( \
  357.             "move\t$4, %1\n\t" \
  358.             "move\t$5, %2\n\t" \
  359.             "move\t$6, %3\n\t" \
  360.             ".set\tnoat\n\t" \
  361.             "addu\t$1, %2, %3\n\t" \
  362.             ".set\tat\n\t" \
  363.             "jal\t__copy_user\n\t" \
  364.             "move\t%0, $6" \
  365.             : "=r" (__cu_len) \
  366.             : "r" (__cu_to), "r" (__cu_from), "r" (__cu_len) \
  367.             : "$4", "$5", "$6", "$8", "$9", "$10", "$11", "$12", \
  368.               "$15", "$24", "$31","memory"); \
  369.     __cu_len; \
  370. })
  371.  
  372. extern inline __kernel_size_t
  373. __clear_user(void *addr, __kernel_size_t size)
  374. {
  375.     __kernel_size_t res;
  376.  
  377.     __asm__ __volatile__(
  378.         "move\t$4, %1\n\t"
  379.         "move\t$5, $0\n\t"
  380.         "move\t$6, %2\n\t"
  381.         "jal\t__bzero\n\t"
  382.         "move\t%0, $6"
  383.         : "=r" (res)
  384.         : "r" (addr), "r" (size)
  385.         : "$4", "$5", "$6", "$8", "$9", "$31");
  386.  
  387.     return res;
  388. }
  389.  
  390. #define clear_user(addr,n) ({ \
  391. void * __cl_addr = (addr); \
  392. unsigned long __cl_size = (n); \
  393. if (__cl_size && __access_ok(VERIFY_WRITE, ((unsigned long)(__cl_addr)), __cl_size)) \
  394. __cl_size = __clear_user(__cl_addr, __cl_size); \
  395. __cl_size; })
  396.  
  397. /*
  398.  * Returns: -EFAULT if exception before terminator, N if the entire
  399.  * buffer filled, else strlen.
  400.  */
  401. extern inline long
  402. __strncpy_from_user(char *__to, const char *__from, long __len)
  403. {
  404.     long res;
  405.  
  406.     __asm__ __volatile__(
  407.         "move\t$4, %1\n\t"
  408.         "move\t$5, %2\n\t"
  409.         "move\t$6, %3\n\t"
  410.         "jal\t__strncpy_from_user_nocheck_asm\n\t"
  411.         "move\t%0, $2"
  412.         : "=r" (res)
  413.         : "r" (__to), "r" (__from), "r" (__len)
  414.         : "$2", "$3", "$4", "$5", "$6", "$8", "$31", "memory");
  415.  
  416.     return res;
  417. }
  418.  
  419. extern inline long
  420. strncpy_from_user(char *__to, const char *__from, long __len)
  421. {
  422.     long res;
  423.  
  424.     __asm__ __volatile__(
  425.         "move\t$4, %1\n\t"
  426.         "move\t$5, %2\n\t"
  427.         "move\t$6, %3\n\t"
  428.         "jal\t__strncpy_from_user_asm\n\t"
  429.         "move\t%0, $2"
  430.         : "=r" (res)
  431.         : "r" (__to), "r" (__from), "r" (__len)
  432.         : "$2", "$3", "$4", "$5", "$6", "$8", "$31", "memory");
  433.  
  434.     return res;
  435. }
  436.  
  437.  
  438. /* Returns: 0 if bad, string length+1 (memory size) of string if ok */
  439. extern inline long __strlen_user(const char *s)
  440. {
  441.     long res;
  442.  
  443.     __asm__ __volatile__(
  444.         "move\t$4, %1\n\t"
  445.         "jal\t__strlen_user_nocheck_asm\n\t"
  446.         "move\t%0, $2"
  447.         : "=r" (res)
  448.         : "r" (s)
  449.         : "$2", "$4", "$8", "$31");
  450.  
  451.     return res;
  452. }
  453.  
  454. extern inline long strlen_user(const char *s)
  455. {
  456.     long res;
  457.  
  458.     __asm__ __volatile__(
  459.         "move\t$4, %1\n\t"
  460.         "jal\t__strlen_user_asm\n\t"
  461.         "move\t%0, $2"
  462.         : "=r" (res)
  463.         : "r" (s)
  464.         : "$2", "$4", "$8", "$31");
  465.  
  466.     return res;
  467. }
  468.  
  469. struct exception_table_entry
  470. {
  471.     unsigned long insn;
  472.     unsigned long nextinsn;
  473. };
  474.  
  475. /* Returns 0 if exception not found and fixup.unit otherwise.  */
  476. extern unsigned long search_exception_table(unsigned long addr);
  477.  
  478. /* Returns the new pc */
  479. #define fixup_exception(map_reg, fixup_unit, pc)                \
  480. ({                                                              \
  481.     fixup_unit;                                             \
  482. })
  483.  
  484. #endif /* __ASM_MIPS_UACCESS_H */
  485.